﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HiSport.Core.Entity.Order;
using Mapster;
using HiSport.Core.Util;
using SqlSugar;
using HiSport.Application.Service.Order.OrderSite.Dtos;
using System.ComponentModel;
using HiSport.Core;
using HiSport.Application.Service.Function.ReserveSiteManagement.Service;
using HiSport.Application.Service.Function.ReserveSiteManagement.Dtos;
using Furion.FriendlyException;
using static HiSport.Application.Service.Function.ReserveSiteManagement.Dtos.SiteDto;
using HiSport.Core.Entity;
using Yitter.IdGenerator;
using HiSport.Application.Service.OrderManage.OrderSiteService.Dtos;
using Microsoft.AspNetCore.Components.Forms;
using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateNewTaxControlFapiaoApplicationRequest.Types.Fapiao.Types;
using System.Runtime.CompilerServices;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.IO;
using HiSport.Core.Entity.HiSportEntity.Bas;

namespace HiSport.Application.Service.Order.OrderSiteService.Service
{

    //[ApiDescriptionSettings("订单管理", Tag = "订场订单管理", SplitCamelCase = false)]
    [ApiDescriptionSettings("OrderManage", Tag = "OrderSite", SplitCamelCase = false)]
    public class OrderSiteService : ITransient, IDynamicApiController, IOrderSiteService
    {
        /// <summary>
        /// 订单主表
        /// </summary>
        private readonly SqlSugarRepository<Core.Entity.Order.OrderSite> _order;
        /// <summary>
        /// 订单子表
        /// </summary>
        private readonly SqlSugarRepository<OrderSiteInfo> _orderInfo;
        private readonly SqlSugarRepository<SysMember> _sysMember;
        /// <summary>
        ///场地计费规则
        /// </summary>
        private readonly SqlSugarRepository<BasSiteBillingRule> _basSiteBillingRule;
        /// <summary>
        ///计费规则
        /// </summary>
        private readonly SqlSugarRepository<BasBillingRule> _basBillingRule;
        /// <summary>
        ///计费规则详情
        /// </summary>
        private readonly SqlSugarRepository<BasBillingRuleInfo> _basBillingRuleInfo;
        /// <summary>
        /// 场地类型
        /// </summary>
        private readonly SqlSugarRepository<BasSiteType> _basSiteTypeRep;
        /// <summary>
        /// 场地
        /// </summary>
        private readonly SqlSugarRepository<BasSite> _basSiteRep;
        private readonly IScheduledSiteService _reserveSiteService;

        public OrderSiteService(SqlSugarRepository<Core.Entity.Order.OrderSite> orderInfo,
            SqlSugarRepository<OrderSiteInfo> orderSiteInfo,
            SqlSugarRepository<SysMember> sysMember,
            IScheduledSiteService reserveSiteService,
            SqlSugarRepository<BasSiteBillingRule> basSiteBillingRule,
            SqlSugarRepository<BasBillingRule> basBillingRule,
            SqlSugarRepository<BasBillingRuleInfo> billingRuleInfo,
            SqlSugarRepository<BasSite> basSite,
            SqlSugarRepository<BasSiteType> basSiteType)
        {
            _order = orderInfo;
            _orderInfo = orderSiteInfo;
            _reserveSiteService = reserveSiteService;
            _sysMember = sysMember;
            _basSiteBillingRule = basSiteBillingRule;
            _basBillingRule = basBillingRule;
            _basBillingRuleInfo = billingRuleInfo;
            _basSiteRep = basSite;
            _basSiteTypeRep = basSiteType;
        }

        /// <summary>
        /// 分页获取订场订单
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [ApiDescriptionSettings(Name = "Page"), HttpPost]
        [DisplayName("分页获取订场订单")]
        public async Task<SqlSugarPagedList<OrderSiteDto>> Page(OrderSitePageInputDto inputDto)
        {

            var memberId = await _sysMember.AsQueryable()
                .Where(x => x.Name.Contains(inputDto.MemberInfo))
                .Select(x => x.Id)
                .ToListAsync();

            var result = await _order.AsQueryable()
                .WhereIF(inputDto.ScheduledTimeStart.HasValue, x => x.ScheduledTime >= inputDto.ScheduledTimeStart.Value.Date)
                .WhereIF(inputDto.ScheduledTimeEnd.HasValue, x => x.ScheduledTime <= inputDto.ScheduledTimeEnd.Value.Date)
                .WhereIF(inputDto.OrderTimeStart.HasValue, x => x.CreateTime >= inputDto.OrderTimeStart.Value.Date)
                .WhereIF(inputDto.OrderTimeEnd.HasValue, x => x.CreateTime <= inputDto.OrderTimeEnd.Value.Date)
                .WhereIF(inputDto.SiteTypeId.HasValue, x => x.SiteTypeId <= inputDto.SiteTypeId)
                .WhereIF(inputDto.SiteId.HasValue, x => x.SiteId <= inputDto.SiteId)
                .WhereIF(!string.IsNullOrEmpty(inputDto.MemberInfo), x =>
                    x.Phone.Contains(inputDto.MemberInfo) || memberId.Contains(x.MemberId))
                .WhereIF(inputDto.OrderSource.HasValue, x => x.OrderSource == inputDto.OrderSource)
                .WhereIF(inputDto.OrderState.HasValue, x => x.OrderState == inputDto.OrderState)
                .OrderBy(u => u.ScheduledTime, OrderByType.Desc)
                .Select(u => new OrderSiteDto()
                {
                    Id = u.Id.SelectAll(),
                })
                .ToPagedListAsync(inputDto.Page, inputDto.PageSize);

            var siteTypeIds = result.Items.Select(x => x.SiteTypeId).ToList();
            var siteIds = result.Items.Select(x => x.SiteId).ToList();

            var siteTypeList = await _basSiteTypeRep.AsQueryable().Where(x => siteTypeIds.Contains(x.Id)).ToListAsync();
            var siteList = await _basSiteRep.AsQueryable().Where(x => siteIds.Contains(x.Id)).ToListAsync();
            foreach (var item in result.Items)
            {
                var siteType = siteTypeList.FirstOrDefault(x=>x.Id==item.SiteTypeId);
                var site = siteList.FirstOrDefault(x => x.Id == item.SiteId);
                item.SiteTypeName = siteType?.SiteTypeName?? string.Empty;
                item.SiteName=site?.SiteName?? string.Empty;
            }

            return result;
        }


        /// <summary>
        /// 更具订场 id 获取订场详情
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [DisplayName("更具 订场id 获取订场详情")]
        public async Task<OrderSiteDto> GetOrderSiteInfo(long orderSiteId)
        {
            var order = await _order.AsQueryable().Where(x => x.Id == orderSiteId).Select(x => new OrderSiteDto()
            {
                Id = x.Id.SelectAll(),

            }).FirstAsync();

            var orderInfos = await _orderInfo.AsQueryable().Where(x => x.OrderSiteId == orderSiteId).Select(x => new OrderSiteInfoDto()
            {
                Id = x.Id.SelectAll(),

            }).ToListAsync();
            order.OrderInfos = orderInfos;
            return order;
        }

        /// <summary>
        /// 更具订场 订单编号 获取订场详情
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [DisplayName("更具订单编号获取订场详情")]
        public async Task<OrderSiteDto> GetOrderSiteInfoByOrderNum(string orderNum)
        {
            var order = await _order.AsQueryable().Where(x => x.OrderNum == orderNum).Select(x => new OrderSiteDto()
            {
                Id = x.Id.SelectAll(),

            }).FirstAsync();
            if (order == null)
            {
                throw Oops.Oh($"【{orderNum}】没有查询到订单信息");
            }

            var orderInfos = await _orderInfo.AsQueryable().Where(x => x.OrderSiteId == order.Id).Select(x => new OrderSiteInfoDto()
            {
                Id = x.Id.SelectAll(),

            }).ToListAsync();
            order.OrderInfos = orderInfos;
            return order;
        }

        /// <summary>
        /// 创建订场订单
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        [ApiDescriptionSettings(Name = "Create"), HttpPost]
        [DisplayName("创建订场订单")]
        public async Task<long> Create(OrderSiteCreateDto inputDto)
        {
            //1.创建主订单
            var orderData = inputDto.Adapt<Core.Entity.Order.OrderSite>();
            orderData.OrderNum = FunctionUtil.GetOrderNum(OrderNumType.DC);
            orderData.OrderSource = inputDto.OrderSource.HasValue ? OrderSourceEnum.Background : orderData.OrderSource;

            //重新计算订单价格，忽略前端传的
            var price = await GetOrderPrice(inputDto.OrderSiteInfos, inputDto.MemberId > 0);
            orderData.ActualPayAmount = 0;
            orderData.PayableAmount = price.payableAmount;
            orderData.TotalAmount = price.totalAmount;
            orderData.DiscountAmount = orderData.TotalAmount - orderData.PayableAmount;


            orderData.Id = YitIdHelper.NextId();
            await _order.InsertAsync(orderData);

            //2.创建子订单
            var orderInfoData = new List<OrderSiteInfo>();
            foreach (var item in inputDto.OrderSiteInfos)
            {
                var info = price.priceInfo.Where(x => x.Key == item);
                orderInfoData.Add(new OrderSiteInfo()
                {
                    StartTime = item.StartTime,
                    EndTime = item.EndTime,
                    OrderSiteId = orderData.Id,
                    SiteId = item.SiteId,
                    SiteTypeId = item.SiteTypeId,
                    ScheduledSiteState = ScheduledSiteStateEnum.OfflineUnpaid,
                    ScheduledTime = inputDto.ScheduledTime.Date,
                    ActualPayAmount = inputDto.MemberId > 0 ? info.First().Value.priceVip : info.First().Value.price,
                    OriginalPrice = info.First().Value.price
                });
            }

            //验证场地是否可以预定
            await _reserveSiteService.SiteCheck(orderInfoData.Select(x => new SiteCheckDto()
            {
                EndTime = x.EndTime,
                SiteId = x.SiteId,
                StartTime = x.StartTime,
                Time = x.ScheduledTime
            }).ToList());

            await _orderInfo.InsertRangeAsync(orderInfoData.ToArray());

            return orderData.Id;
        }

        /// <summary>
        /// 取消全部订场订单（订单编号）
        /// </summary>
        /// <param name="orderNum"></param>
        /// <returns></returns>
        [UnitOfWork]
        [DisplayName("取消全部订场订单")]
        public async Task<bool> CancelAllOrderSite(string orderNum)
        {
            //查询订单
            var orderSite = await _order.GetFirstAsync(x => x.OrderNum == orderNum);
            if (orderSite == null)
            {
                throw Oops.Oh($"【{orderNum}】没有查询到订单信息");
            }
            orderSite.OrderState = OrderStateEnum.AllCancel;
            await _order.UpdateAsync(orderSite);

            //子订单
            var orderSiteinfo = await _orderInfo.GetListAsync(x => x.OrderSiteId == orderSite.Id);
            if (orderSiteinfo.Count() <= 0)
            {
                throw Oops.Oh($"【{orderNum}】订单没有订场信息");
            }


            await _orderInfo.UpdateRangeAsync(orderSiteinfo);

            return true;
        }

        /// <summary>
        /// 取消部分订场 订场子订单（根据orderSiteInfoId）
        /// </summary>
        /// <returns></returns>
        [UnitOfWork]
        [DisplayName("取消部分订场")]
        public async Task<bool> CancelPartOrderSite(List<long> OrderSiteInfoIds)
        {
            //子订单
            var orderSiteinfos = await _orderInfo.GetListAsync(x => OrderSiteInfoIds.Contains(x.Id));
            if (orderSiteinfos.Count <= 0)
            {
                throw Oops.Oh($"没有查询到订场信息");
            }
            var orderIdList = orderSiteinfos.GroupBy(x => x.OrderSiteId).Select(x => x.Key);
            if (orderIdList.Count() > 1)
            {
                throw Oops.Oh($"不能跨订单操作");
            }
            var orderId = orderIdList.FirstOrDefault();
            await _orderInfo.FakeDeleteAsync(orderSiteinfos);

            //查询订单
            var orderSite = await _order.GetFirstAsync(x => x.Id == orderId);
            if (orderSite == null)
            {
                throw Oops.Oh($"订场信息不存在");
            }

            if (orderSite.OrderPayState == OrderPayStateEnum.AllPayment)
            {
                //添加退款信息
            }
            orderSite.OrderState = orderSiteinfos.Count == 0 ? OrderStateEnum.AllCancel : OrderStateEnum.PartialCancel;
            await _order.UpdateAsync(orderSite);
            return true;

        }

        /// <summary>
        /// 追加订场
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [DisplayName("追加订场")]
        public async Task<bool> AddPartOrderSite(List<OrderSiteInfoCreateDto> inputDto)
        {
            //2.创建子订单
            var orderInfoData = new List<OrderSiteInfo>();
            foreach (var item in inputDto)
            {
                orderInfoData.Add(new OrderSiteInfo()
                {
                    StartTime = item.StartTime,
                    EndTime = item.EndTime,
                    OrderSiteId = item.OrderId,
                    ActualPayAmount = item.ActualPayAmount,
                    SiteId = item.SiteId,
                    SiteTypeId = item.SiteTypeId,
                    ScheduledSiteState = ScheduledSiteStateEnum.OfflineUnpaid,
                    ScheduledTime = item.ScheduledTime,
                });
            }

            //验证场地是否可以预定
            await _reserveSiteService.SiteCheck(orderInfoData.Select(x => new SiteCheckDto()
            {
                EndTime = x.EndTime,
                SiteId = x.SiteId,
                StartTime = x.StartTime,
                Time = x.ScheduledTime
            }).ToList());

            return await _orderInfo.InsertRangeAsync(orderInfoData.ToArray());
        }


        /// <summary>
        /// 获取订单价格  
        /// </summary>
        /// <returns></returns>
        private async Task<(decimal totalAmount, decimal payableAmount, Dictionary<OrderSiteInfoCreateDto, (decimal price, decimal priceVip)> priceInfo)> GetOrderPrice(List<OrderSiteInfoCreateDto> inputDto, bool isMember)
        {
            var totalAmount = new decimal(0);
            var payableAmount = new decimal(0);
            var priceInfo = new Dictionary<OrderSiteInfoCreateDto, (decimal price, decimal priceVip)>();


            //所有场地
            var siteIdList = inputDto.Select(x => x.SiteId).Distinct().ToList();

            //查询场地配置的计费规则
            var billingRule = await _basSiteBillingRule.AsQueryable()
                .Where(x => siteIdList.Contains(x.SiteId) && x.Status == StatusEnum.Enable)
                .OrderBy(x => x.Sort)
                .ToListAsync();

            var billingRuleId = billingRule.Select(x => x.BillingRuleId).ToList();

            //查询接规则
            billingRuleId = await _basBillingRule.AsQueryable()
                .Where(x => billingRuleId.Contains(x.Id) && x.Status == StatusEnum.Enable)
                .Select(x => x.Id)
                .ToListAsync();

            //查询计费规则详情
            var billingRuleInfoList = await _basBillingRuleInfo.AsQueryable()
                .Where(x => billingRuleId.Contains(x.BillingRuleId)).ToListAsync();

            foreach (var item in inputDto)
            {
                //场地的计费规则
                var v1 = billingRule.Where(x => x.SiteId == item.SiteId).ToList();
                //场地的计费规则主id
                var vid = billingRule.Select(x => x.BillingRuleId).ToList();
                //计费规则详情
                var v2 = billingRuleInfoList.Where(x => vid.Contains(x.BillingRuleId)).ToList();

                var price = GetSitePrice(v1, v2, item.StartTime, item.EndTime);
                totalAmount += price.price;
                if (isMember)
                {
                    payableAmount += price.unifyPriceVip;
                }
                else
                {
                    payableAmount += price.price;
                }

                priceInfo.Add(item, (price.price, price.unifyPriceVip));
            }
            return (totalAmount, payableAmount, priceInfo);
        }


        /// <summary>
        /// 获取价格
        /// </summary>
        /// <param name="billingRule"></param>
        /// <param name="billingRuleInfoList"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        private (decimal price, decimal unifyPriceVip, Dictionary<long, decimal> priceVip) GetSitePrice(List<BasSiteBillingRule> billingRule, List<BasBillingRuleInfo> billingRuleInfoList, string startTime, string endTime)
        {
            //普通价格
            var price = new decimal(0);

            //同意VIP价格
            var unifyPriceVip = new decimal(0);

            //VIP详细价格
            var priceVip = new Dictionary<long, decimal>();


            foreach (var item in billingRule)
            {
                var infoList = billingRuleInfoList.Where(x => x.BillingRuleId == item.BillingRuleId);
                foreach (var info in infoList)
                {

                    var infoStartTime = Convert.ToDateTime(info.StartTime.ToString() + ":00");
                    var infoEndTime = Convert.ToDateTime("00:00");
                    if (info.EndTime == 24)
                    {
                        infoEndTime = Convert.ToDateTime("23:59");
                    }

                    //时间段类 符合的价格
                    if (Convert.ToDateTime(startTime) >= infoStartTime)
                    {
                        if (Convert.ToDateTime(endTime) <= infoEndTime)
                        {
                            price = info.Price;
                            unifyPriceVip = info.MemberPriceType == MemberPriceTypeEnum.Unify ? info.MemberUnifyPrice : 0;
                            priceVip.Add(0, 0);
                            return (price, unifyPriceVip, priceVip);
                        }
                    }
                }

            }

            return (price, unifyPriceVip, priceVip);
        }
    }
}
